package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
	"web_app/controller"
	"web_app/dao/mysql"
	"web_app/dao/redis"
	"web_app/logger"
	"web_app/pkg/snowflake"
	"web_app/routes"
	"web_app/setting"

	"github.com/spf13/viper"

	"go.uber.org/zap"
)

//Go Web开发较通用的脚手架模板
//@title bluebell_backend
//@version 1.0
//@description bluebell_backend测试
//@termsOfService http://swagger.io/terms/
//
//@contact.name author：@huchao
//@contact.url http://www.swagger.io/support
//@contact.email support@swagger.io
//
//@license.name Apache 2.0
//@license.url http://www.apache.org/licenses/LICENSE-2.0.html
//
//@host 127.0.0.1:8081
//@BasePath /api/v1/

//新版代码
func main() {
	/**
	1.加载配置
	2.初始化日志
	3.初始化mysql
	4.初始化redis
	5.注册路由
	6.启动服务（优雅关机）
	*/

	//1.加载配置
	if err := setting.Init(); err != nil {
		fmt.Printf("init setttings failed, err :%v\n", err)
		return
	}

	//2.初始化日志
	if err := logger.Init(setting.Conf.LogConfig, setting.Conf.Mode); err != nil {
		fmt.Printf("init logger failed, err :%v\n", err)
		return
	}
	defer zap.L().Sync()
	zap.L().Debug("logger init success...")

	//3.初始化mysql
	if err := mysql.Init(setting.Conf.MySQLConfig); err != nil {
		fmt.Printf("init mysql failed, err :%v\n", err)
		return
	}
	defer mysql.Close()

	//4.初始化redis
	if err := redis.Init(setting.Conf.RedisConfig); err != nil {
		fmt.Printf("init redis failed, err :%v\n", err)
		return
	}
	defer redis.Close()

	//7. 使用雪花算法 生成用户id
	if err := snowflake.Init(setting.Conf.SnowFlakeConfig); err != nil {
		fmt.Printf("init snowflake failed, err :%v\n", err)
		return
	}

	//8.初始化gin框架内置的校验器 使用的翻译器
	if err := controller.InitTrans("zh"); err != nil {
		fmt.Printf("init validator trans failed, err :%v\n", err)
		return
	}

	//5.注册路由
	r := routes.SetupRouter()

	//6.启动服务（优雅关机）
	srv := &http.Server{
		Addr:    fmt.Sprintf(":%d", viper.GetInt("app.port")),
		Handler: r,
	}
	go func() {
		//开启一个goroutine 启动服务
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			log.Fatalf("listen:%s\n", err)
		}
	}()
	quit := make(chan os.Signal, 1)
	//kill 默认会发送 syscall.SIGTERM 信号
	//kill -2 发送 syscall.SIGINT 信号 我们常用的Ctrl+C就是触发系统SIGINT信号
	//kill -9 发送 syscall.SIGKILL 信号 但不能被捕获，不需要添加
	//signal.Notify把收到的syscall.SIGINT或syscall.SIGKILL 信号转发给quit
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
	//从管道中接收值 忽略结果
	//阻塞在此 当接收到上述两种信号时才会往下执行
	<-quit
	zap.L().Info("Shutdown Server ...")
	//创建一个5秒后超时的context
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	//5秒内优雅关闭服务（将未处理完的请求处理完再关闭服务），超过5秒就超时退出
	if err := srv.Shutdown(ctx); err != nil {
		zap.L().Fatal("Server Shutdown: ", zap.Error(err))
	}
	log.Println("Server exiting")
}

//旧版代码 setting.Init() 将配置文件信息读取到viper中
//func main() {
//	/**
//	1.加载配置
//	2.初始化日志
//	3.初始化mysql
//	4.初始化redis
//	5.注册路由
//	6.启动服务（优雅关机）
//	*/
//
//
//	//1.加载配置
//	if err := setting.Init(); err != nil {
//		fmt.Printf("init setttings failed, err :%v\n", err)
//		return
//	}
//
//	//2.初始化日志
//	if err := logger.Init(); err != nil {
//		fmt.Printf("init logger failed, err :%v\n", err)
//		return
//	}
//	defer zap.L().Sync()
//	zap.L().Debug("logger init success...")
//
//	//3.初始化mysql
//	if err := mysql.Init(); err != nil {
//		fmt.Printf("init mysql failed, err :%v\n", err)
//		return
//	}
//	defer mysql.Close()
//
//	//4.初始化redis
//	if err := redis.Init(); err != nil {
//		fmt.Printf("init redis failed, err :%v\n", err)
//		return
//	}
//	defer redis.Close()
//
//	//5.注册路由
//	r := routes.SetupRouter()
//
//	//6.启动服务（优雅关机）
//	srv := &http.Server{
//		Addr:    fmt.Sprintf(":%d", viper.GetInt("app.port")),
//		Handler: r,
//	}
//	go func() {
//		//开启一个goroutine 启动服务
//		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
//			log.Fatalf("listen:%s\n", err)
//		}
//	}()
//	quit := make(chan os.Signal, 1)
//	//kill 默认会发送 syscall.SIGTERM 信号
//	//kill -2 发送 syscall.SIGINT 信号 我们常用的Ctrl+C就是触发系统SIGINT信号
//	//kill -9 发送 syscall.SIGKILL 信号 但不能被捕获，不需要添加
//	//signal.Notify把收到的syscall.SIGINT或syscall.SIGKILL 信号转发给quit
//	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
//	//从管道中接收值 忽略结果
//	//阻塞在此 当接收到上述两种信号时才会往下执行
//	<-quit
//	zap.L().Info("Shutdown Server ...")
//	//创建一个5秒后超时的context
//	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
//	defer cancel()
//	//5秒内优雅关闭服务（将未处理完的请求处理完再关闭服务），超过5秒就超时退出
//	if err := srv.Shutdown(ctx); err != nil {
//		zap.L().Fatal("Server Shutdown: ", zap.Error(err))
//	}
//	log.Println("Server exiting")
//}
